#include <iostream>
#include <string>
#include <time.h>
#include <sstream>
#include <iomanip>
#include "PosMenu.h"
#include "Usb.h"
#include "HardDisk.h"
#include "Monitor.h"
#include "SDcard.h"
#include "AppSoftware.h"

using namespace std;

/*
*	Class constructor.
*/
PosMenu::PosMenu() 
{

}

/*
*	Function browseAllItems displays all products.
*/
void PosMenu::browseAllItems()
{
	browseSpecificItems("usb");
	cout << endl;
	browseSpecificItems("harddisk");
	cout << endl;
	browseSpecificItems("monitor");
	cout << endl;
	browseSpecificItems("sdcard");
	cout << endl;
	browseSpecificItems("appsoftware");
}
/*
*	Function browseItemsBelowThresholdValue gets the products that below the Threshold Value.
*/

void PosMenu::browseItemsBelowThresholdValue()
{
	int thresholdValue;

	cout << "Please enter the Threshold Value: ";
	cin >> thresholdValue;
	vector<Products *> productsList = getProductsList();
	vector<Products *> displayProductsList;// For display the product in the specific format
	for(int i=0; i < productsList.size(); i++) {
		if(productsList[i]->getStock()<thresholdValue){
			displayProductsList.push_back(productsList[i]);
		}
		else
		{
			displayProductsList.push_back(0); // Keep the product index the same as the Product list
		}
	}
	if(displayListSize( displayProductsList)!=0){
		displayProductsFromSpecificList(displayProductsList); // Display the result list
	}
	else
	{
		cout << "[Warning] No items below the Threshold Value : "<<thresholdValue<<endl;
	}
	displayProductsList.clear();
}
/*
*	Function browseSpecificItems displays specific type of products.
*
*	@param type the type of product.
*/
void PosMenu::browseSpecificItems(string type)
{
	vector <Products *> products = getProductsList();

	if(type.compare("usb") == 0)
	{
		cout << "USB" << endl;
		cout << left << "[IDX]" << " | " << setw(10) << "Product ID" << " | " << setw(10) << "Brand" 
			<< " | " <<  setw(8) << "Price" << " | " << setw(5) << "Stock" 
			<< " | " << setw(12) << "Memory Size" << " | " << setw(10) << "Color";
		cout << endl << setfill('-') << setw(75) << "-" << endl;

		for(int i = 0; i < products.size(); i++)
		{
			// downcast pointer
			Usb *derivedPtr = dynamic_cast < Usb * >( products[i] );

			if(derivedPtr != 0 ) // 0 - if product is not a usb 
			{
				cout << " [" << setfill(' ') << setw(2) << i << "] ";
				displaySpecificItems(derivedPtr);
			} // end if

		} // end for 

	}

	else if (type.compare("harddisk") == 0)
	{
		cout << "Hard Disk" << endl;
		cout << left << "[IDX]" << " | "<< setw(10) << "Product ID" << " | "<< setw(10) << "Brand" 
			<< " | " << setw(8) << "Price" << " | " << setw(5) << "Stock" 
			<< " | " << setw(12) << "Memory Size" << " | " << setw(10) << "Protable";
		cout << endl << setfill('-') << setw(76) << "-" << endl;

		for(int i = 0; i < products.size(); i++)
		{
			// downcast pointer
			HardDisk *derivedPtr = dynamic_cast < HardDisk * >( products[i] );

			if(derivedPtr != 0 ) // 0 - if product is not a harddisk
			{
				cout << " [" << setfill(' ') << setw(2) << i << "] ";
				displaySpecificItems(derivedPtr);
			} // end if

		} // end for 

	}

	else if (type.compare("monitor") == 0)
	{
		cout << "Monitor" << endl;
		cout << left << "[IDX]" << " | " << setw(10) << "Product ID" << " | " << setw(10) << "Brand" 
			<< " | " <<  setw(8) << "Price" << " | " << setw(5) << "Stock" << " | " << setw(12) << "Monitor Size";
		cout << endl << setfill('-') << setw(65) << "-" << endl;

		for(int i = 0; i < products.size(); i++)
		{
			// downcast pointer
			Monitor *derivedPtr = dynamic_cast < Monitor * >( products[i] );

			if(derivedPtr != 0 ) // 0 - if product is not a monitor 
			{
				cout << " [" << setfill(' ') << setw(2) << i << "] ";
				displaySpecificItems(derivedPtr);
			} // end if

		} // end for 
	}

	else if (type.compare("sdcard") == 0)
	{
		cout << "SD Card" << endl;
		cout << left << "[IDX]" << " | " << setw(10) << "Product ID" << " | " << setw(10) << "Brand" 
			<< " | " <<  setw(8) << "Price" << " | " << setw(5) << "Stock" 
			<< " | " << setw(12) << "Memory Size"  << " | " << setw(8) << "Type";
		cout << endl << setfill('-') << setw(76) << "-" << endl;

		for(int i = 0; i < products.size(); i++)
		{
			// downcast pointer
			SDcard *derivedPtr = dynamic_cast < SDcard * >( products[i] );

			if(derivedPtr != 0 ) // 0 - if product is not a sd card
			{
				cout << " [" << setfill(' ') << setw(2) << i << "] ";
				displaySpecificItems(derivedPtr);
			} // end if

		} // end for 
	}

	else if (type.compare("appsoftware") == 0)
	{
		cout << "Application Software" << endl;
		cout << left << "[IDX]" << " | " << setw(10) << "Product ID" << " | " << setw(10) << "Brand" 
			<< " | " <<  setw(8) << "Price" << " | " << setw(5) << "Stock" 
			<< " | " << setw(20) << "Title"  << " | " << setw(10) << "Language" << " |" << setw(10) << "Version";
		cout << endl << setfill('-') << setw(95) << "-" << endl;

		for(int i = 0; i < products.size(); i++)
		{
			// downcast pointer                        
			AppSoftware *derivedPtr = dynamic_cast < AppSoftware * >( products[i] );

			if(derivedPtr != 0 ) // 0 - if product is not a application software 
			{
				cout << " [" << setfill(' ') << setw(2) << i << "] ";
				displaySpecificItems(derivedPtr);
			} // end if

		} // end for 
	}
	else
	{
		cout << "[Warning] Invalid input"<<endl;
	}
}

/*
*	Function displayProductsFromSpecificList display a list of products in the Special Format.
*/
void PosMenu::displayProductsFromSpecificList( vector <Products *> products)
{

	int displayTitleCount =0;
	for(int i = 0; i < products.size(); i++)
	{
		// downcast pointer
		Usb *derivedPtr = dynamic_cast < Usb * >( products[i] );

		if(derivedPtr != 0 ) // 0 - if product is not a usb 
		{
			if(displayTitleCount==0)
			{
				cout << "USB" << endl;
				cout << left << "[IDX]" << " | " << setw(10) << "Product ID" << " | " << setw(10) << "Brand" 
					<< " | " <<  setw(8) << "Price" << " | " << setw(5) << "Stock" 
					<< " | " << setw(12) << "Memory Size" << " | " << setw(10) << "Color";
				cout << endl << setfill('-') << setw(75) << "-" << endl;
				displayTitleCount++;
			}
			cout << " [" << setfill(' ') << setw(2) << i << "] ";
			displaySpecificItems(derivedPtr);
		} // end if

	} // end for 


	displayTitleCount=0;

	for(int i = 0; i < products.size(); i++)
	{
		// downcast pointer
		HardDisk *derivedPtr = dynamic_cast < HardDisk * >( products[i] );

		if(derivedPtr != 0 ) // 0 - if product is not a harddisk
		{
			if(displayTitleCount==0)
			{
				cout << "Hard Disk" << endl;
				cout << left << "[IDX]" << " | "<< setw(10) << "Product ID" << " | "<< setw(10) << "Brand" 
					<< " | " << setw(8) << "Price" << " | " << setw(5) << "Stock" 
					<< " | " << setw(12) << "Memory Size" << " | " << setw(10) << "Protable";
				cout << endl << setfill('-') << setw(76) << "-" << endl;
				displayTitleCount++;
			}
			cout << " [" << setfill(' ') << setw(2) << i << "] ";
			displaySpecificItems(derivedPtr);
		} // end if

	} // end for 

	displayTitleCount=0;


	for(int i = 0; i < products.size(); i++)
	{
		// downcast pointer
		Monitor *derivedPtr = dynamic_cast < Monitor * >( products[i] );

		if(derivedPtr != 0 ) // 0 - if product is not a monitor 
		{
			if(displayTitleCount==0)
			{
				cout << "Monitor" << endl;
				cout << left << "[IDX]" << " | " << setw(10) << "Product ID" << " | " << setw(10) << "Brand" 
					<< " | " <<  setw(8) << "Price" << " | " << setw(5) << "Stock" << " | " << setw(12) << "Monitor Size";
				cout << endl << setfill('-') << setw(65) << "-" << endl;
				displayTitleCount++;
			}
			cout << " [" << setfill(' ') << setw(2) << i << "] ";
			displaySpecificItems(derivedPtr);
		} // end if

	} // end for 



	displayTitleCount=0;
	for(int i = 0; i < products.size(); i++)
	{
		// downcast pointer
		SDcard *derivedPtr = dynamic_cast < SDcard * >( products[i] );

		if(derivedPtr != 0 ) // 0 - if product is not a sd card
		{
			if(displayTitleCount==0)
			{
				cout << "SD Card" << endl;
				cout << left << "[IDX]" << " | " << setw(10) << "Product ID" << " | " << setw(10) << "Brand" 
					<< " | " <<  setw(8) << "Price" << " | " << setw(5) << "Stock" 
					<< " | " << setw(12) << "Memory Size"  << " | " << setw(8) << "Type";
				cout << endl << setfill('-') << setw(76) << "-" << endl;
				displayTitleCount++;
			}
			cout << " [" << setfill(' ') << setw(2) << i << "] ";
			displaySpecificItems(derivedPtr);
		} // end if

	} // end for 
	displayTitleCount=0;


	for(int i = 0; i < products.size(); i++)
	{
		// downcast pointer                        
		AppSoftware *derivedPtr = dynamic_cast < AppSoftware * >( products[i] );

		if(derivedPtr != 0 ) // 0 - if product is not a application software 
		{
			if(displayTitleCount==0)
			{
				cout << "Application Software" << endl;
				cout << left << "[IDX]" << " | " << setw(10) << "Product ID" << " | " << setw(10) << "Brand" 
					<< " | " <<  setw(8) << "Price" << " | " << setw(5) << "Stock" 
					<< " | " << setw(20) << "Title"  << " | " << setw(10) << "Language" << " |" << setw(10) << "Version";
				cout << endl << setfill('-') << setw(95) << "-" << endl;
				displayTitleCount++;
			}
			cout << " [" << setfill(' ') << setw(2) << i << "] ";
			displaySpecificItems(derivedPtr);
		} // end if

	} // end for 


}



/*
*	Function restockItem updates the quantity of selected product.
*
*	@param product the selected product.
*	@param quantity	the quantity of product.
*/
void PosMenu::restockItem(Products *product, int quantity)
{
	if(quantity > 0)
	{
		product->setStock(product->getStock() + quantity);
		cout << product->getPid() << " successful updated."<<endl;
	}
	else
		cout << "[Warning]: Quantity must be greater than 0."<<endl;
}

/////////////////////////////////////////////////////////
//	Search Functions
/////////////////////////////////////////////////////////

/*
*	Function searchItemByPid search product by product id.
*
*	@param pid the id of product.
*/
void PosMenu::searchItemByPid(string pid)
{
	vector <Products *> products = getProductsList();
	vector<Products *> displayProductsList;
	if(!pid.empty())
	{
		for(int i = 0; i < products.size(); i++)
		{
			if(products[i]->getPid().compare(pid) == 0)
			{
				displayProductsList.push_back(products[i]);
			}
			else
			{
				displayProductsList.push_back(0); // Keep the product index the same as the Product list
			}
		}

		if(	displayListSize( displayProductsList)!=0) // not empty list
		{
			displayProductsFromSpecificList(displayProductsList); // Display the result list
			displayProductsList.clear();
		}
		else
		{
			cout<< "[Warning] product cannot find!"<<endl;
		}



	}
}

/*
*	Function searchItemByPid search products by product brand.
*
*	@param brand the brand of product.
*/
void PosMenu::searchItemByBrand(string brand)
{
	vector <Products *> products = getProductsList();
	vector<Products *> displayProductsList;
	if(!brand.empty())
	{
		for(int i = 0; i < products.size(); i++)
		{
			if(products[i]->getBrand().compare(brand) == 0){
				displayProductsList.push_back(products[i]);
			}	else
			{
				displayProductsList.push_back(0); // Keep the product index the same as the Product list
			}

		}
		if(displayListSize( displayProductsList)!=0) // not empty list
		{
			displayProductsFromSpecificList(displayProductsList);// Display the result list
			displayProductsList.clear();
		}
		else
		{
			cout<< "[Warning] product cannot find!"<<endl;
		}
	}
}

/*
*	Function searchItemByPid search products by product stock.
*
*	@param stock the stock of product.
*/
void PosMenu::searchItemByStock(int stock)
{
	vector <Products *> products = getProductsList();
	vector<Products *> displayProductsList;
	if(stock > 0)
	{
		for(int i = 0; i < products.size(); i++)
		{
			if(products[i]->getStock() == stock){
				displayProductsList.push_back(products[i]);
			}
			else
			{
				displayProductsList.push_back(0); // Keep the product index the same as the Product list
			}
		} 
		if(displayListSize( displayProductsList)!=0) // not empty list
		{
			displayProductsFromSpecificList(displayProductsList);// Display the result list
			displayProductsList.clear();
		}
		else
		{
			cout<< "[Warning] product cannot find!"<<endl;
		}
	}
}

/*
*	Function searchItemByPid search products by product price.
*
*	@param price the price of product.
*/
void PosMenu::searchItemByPrice(int price)
{
	vector <Products *> products = getProductsList();
	vector<Products *> displayProductsList;
	if(price > 0)
	{
		for(int i = 0; i < products.size(); i++)
		{
			if(products[i]->getPrice() == price)
			{
				displayProductsList.push_back(products[i]);
			}	
			else
			{
				displayProductsList.push_back(0); // Keep the product index the same as the Product list
			}
		}
		if(displayListSize( displayProductsList)!=0) // not empty list
		{
			displayProductsFromSpecificList(displayProductsList);// Display the result list
			displayProductsList.clear();
		}
		else
		{
			cout<< "[Warning] product cannot find!"<<endl;
		}
	}
}

/////////////////////////////////////////////////////////
//	End of Search Functions
/////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////
//	Sorting
/////////////////////////////////////////////////////////
/*
*	Function sortProductList sorts the products list.
*/
void PosMenu::sortProductsList()
{
	cout << "------------------------------------------------------";
	cout << "\n[Testing - Sorting by price]";
	// Testing --- sort product by price
	sortByPrice();
	browseSpecificItems("usb");

	cout << endl;
	cout << "------------------------------------------------------";
	// Testing --- sort product by Stock
	cout << "\n[Testing - Sorting by stock]";
	sortByStock();
	browseSpecificItems("usb");

	cout << endl;
	cout << "------------------------------------------------------";
	// Testing --- sort product by brand
	cout << "\n[Testing - Sorting by brand]";
	sortByBrand();
	//browseSpecificItems("usb");
	browseAllItems();

}
/*
*	Function swap swap the two elements in the list.
*/
void PosMenu::swap(vector<Products *> productsList, int p1, int p2)
{
	Products * tempProduct;
	tempProduct = products[p1];
	products[p1] = products[p2];
	products[p2] = tempProduct;
}
/*
*	Function sortByPrice sort the product list by price
*/
void PosMenu::sortByPrice()
{
	vector<Products *> productsList = getProductsList();

	int i, j;

	for(i = 0; i < (products.size()-1); i++)
	{
		for(j=0; j < (products.size()-(i+1)); j++)
		{
			if(products[j]->getPrice() > products[j+1]->getPrice()) // if the previous price is larger than the next one, swap
				swap(productsList, j, j+1);
		}
	}
}
/*
*	Function sortByBrand sort the product list by brand
*/
void PosMenu::sortByBrand()
{
	vector<Products *> productsList = getProductsList();

	int i, j;

	for(i=0; i < products.size()-1; i++)
	{
		for(j=0; j < (products.size()-(i+1)); j++)
		{
			if(products[j]->getBrand().compare(products[j+1]->getBrand()) > 0)// if the previous brand's first letter alpha order is larger than the next one, swap
				swap(productsList, j, j+1);
		}
	}
}
/*
*	Function sortByStock sort the product list by quantity
*/
void PosMenu::sortByStock()
{
	vector<Products *> productsList = getProductsList();

	int i, j;

	// cout << "\nsize of product vector: " << products.size();

	for(i=0; i < products.size(); i++)
	{
		for(j=0; j < (products.size()-(i+1)); j++)
		{
			if(products[j]->getStock() > products[j+1]->getStock())// if the previous quantity is larger than the next one, swap
				swap(productsList, j, j+1);
		}
	}

	cout << endl;
}

///////////////////////////////////////////////////////////////////////////
//	end of sorting
///////////////////////////////////////////////////////////////////////////

/*
*	Function displaySpecificItems displays specific type of products.
*
*	@param derivedPtr the selected product.
*/
void PosMenu::displaySpecificItems(Products *derivedPtr)
{
	derivedPtr->productInfo();
	cout << endl;
}

/*
*	Function setProductsList sets the products list.
*
*	@param products the products list.
*/
void PosMenu::setProductsList(vector<Products *> products)
{
	this->products = products;
	//cout << "size of vector: " << products.size() << endl;

}

/*
*	Function getProductsList gets the products list.
*/

vector<Products *> PosMenu::getProductsList() 
{
	return products;
}


/*
*	Function getShoppingCart gets the shopping cart.
*/
vector<OrderProduct *> PosMenu::getShoppingCart() 
{
	return shoppingCart;
}

/*
*	Function setShoppingCart sets the shopping cart.
*/
void PosMenu::setShoppingCart(vector<OrderProduct *> shoppingCart)
{
	this->shoppingCart = shoppingCart;


}
/*
*	Function displayListSize get the size of a display product list.
*/
int PosMenu::displayListSize(vector<Products *> displayList)
{
	int count=0;
	for(int i =0;i<displayList.size();i++)
	{
		if(displayList[i]!=0)
		{
			count++;
		}
	}
	return count;
}

/*
*	Function selectProductsIntoShoppingCart allow user to select products and pick up into the cart.
*/
void PosMenu::selectProductsIntoShoppingCart()
{

	bool selectAgainFlag = true; // control the looping of selecting items into the shopping cart
	int loopCount = 0;
	while(selectAgainFlag){// if 1 , continue to select
		if(loopCount>0){ // The first time does not appear this message.
			cout << "Continue shopping? 0 - no, 1 - yes" << endl;
			cin >> selectAgainFlag;
			if(!selectAgainFlag) // if 0 is input, exit the loop
				return;
		}
		loopCount++;

		int itemNo;
		int quantity;
		cout << "Please select product: ";
		cin >> itemNo;
		cout << "Please enter quantity: ";
		cin >> quantity;

		if(!isExistProducts(itemNo)){ // check whether the itemNo is existing or not.
			cout << "[Warning]: Item number does not exist." << endl;
			continue;
		}

		Products * product = new Products();
		product= products[itemNo];
		if(isExistProductInShoppingCart(product)){ // check any repeat item is selected
			cout << "[Warning]: This item is already stored in the shopping cart" << endl;
			continue;
		}

		if(quantity > 0) // Avoid negative number input
		{
			if(quantity <= product->getStock()){ // Avoid out of stock

				OrderProduct *orderProduct = new OrderProduct(product,quantity,(product->getPrice() * quantity));
				shoppingCart.push_back(orderProduct);
				cout << product->getPid() << " successfulyl stored into shopping cart." << endl;
				cout << "no. of items inside the shoppingCart :"<<shoppingCart.size()<<endl;

			}
			else
			{
				cout << "[Warning]:There is not enough stock for you. The total quantity for this stock is "<<product->getStock()<<endl;
				continue;
			}

		}
		else
		{
			cout << "[Warning]: Quantity must be greater than 0." << endl;
			continue;
		}

	}
}
/*
*	Function deduceQuantity deduce the quantity of the prodcut by the pid.
*/
void PosMenu::deduceQuantity(string pid, int quantity)
{
	vector<Products *> products = getProductsList();
	for(int i=0; i < products.size(); i++) {
		if(pid.compare(products[i]->getPid())==0)
		{
			products[i]->setStock(products[i]->getStock() - quantity); // deduce the quantity
			break;
		}
	}
	setProductsList(products);
}
/*
*	Function browseAllItemsInShoppingCart displays the shopping cart items.
*/
void PosMenu::browseAllItemsInShoppingCart()
{
	vector<OrderProduct *> shoppingCart = getShoppingCart();
	if(shoppingCart.size()==0)
	{
		cout<< "[Warning] No item in the shopping cart"<<endl;
		return;
	}

	cout <<setw(21)<< "|"<< setw(10)<<"Pid"<<"|"<< setw(10)<<"Brand"<<"|"<< setw(10)<<"Price"<<"|"<< setw(10)<<"Quantity"<<"|"<< setw(10)<<"Line Amount"<<endl;

	for(int i=0; i < shoppingCart.size(); i++) {
		cout << "Ordered product " <<  i << " - ";
		shoppingCart[i]->OrderProductInfo();
		cout << endl;
	}

}
/*
*	Function clearShoppingCart clear the cart items.
*/
void PosMenu::clearShoppingCart()
{

	shoppingCart.clear();

	cout<< "Shopping cart is clear!"<<endl;
}
/*
*	Function createTransaction create the transaction 
*/
void PosMenu::createTransaction()
{

	vector<OrderProduct *> shoppingCart = getShoppingCart();
	if(shoppingCart.size()==0) // empty shopping cart
	{
		cout<< "[Warning] No item is selected!"<<endl;
		return;
	}

	// deduce the quantity of the corresponding product
	for(int i=0; i < shoppingCart.size(); i++) {
		deduceQuantity(shoppingCart[i]->getProduct()->getPid(),shoppingCart[i]->getQuantity());
	}
	Transaction * transaction = new Transaction();
	time_t t = time(0);   // get time now
	struct tm * now = localtime( &t );

	string date= IntToString (now->tm_year + 1900)+ "-" +IntToString(now->tm_mon + 1)+ "-"+ IntToString(now->tm_mday);

	string time = IntToString(now->tm_hour)+":"+IntToString (now->tm_min);

	string invoiceNo = IntToString (now->tm_year + 1900)+ "" +IntToString(now->tm_mon + 1)+ ""+ IntToString(now->tm_mday)+""+IntToString(now->tm_hour)+""+IntToString (now->tm_min)+""+IntToString (now->tm_sec);
	transaction->setInvoiceNo(invoiceNo);
	transaction->setTDate(date);
	transaction->setTTime(time);
	transaction->setOrderLine(shoppingCart);
	writeTransactionIntoTxt(transaction);
	viewTheLatestInvoice(); // Display the newly transaction detail
	clearShoppingCart();
}

//////////////////////////////////////////////////////////////////////////
// Transaction

void PosMenu::viewInvoiceDetail()
{
	string inputInvoiceNo;
	cout << "Please enter the invoice number: ";
	cin >> inputInvoiceNo;

	Transaction * transaction = readTransactionByInvoiceNo(inputInvoiceNo);

	if(transaction!=0)
	{
		cout<< "Invoice found! " <<endl;
		transaction->TransactionInfo();
	}
	else
	{
		cout<< "[Warning] Invoice not found! " <<endl;
	}

}

/*
*	Function writeTransactionIntoTxt write the transaction into the Transaction.txt 
*/
void PosMenu::writeTransactionIntoTxt(Transaction * transaction){
	fstream file; 
	file.open("Transaction.txt", ios::out | ios::app );
	double totalAmount = 0;
	if(file)     // file opened
	{
		file << "Invoice Number: " << transaction->getInvoiceNo() <<endl << "Date: " << transaction->getTDate()<<endl  << "Time: " << transaction->getTTime() << endl;

		vector<OrderProduct *> orderLine = transaction->getOrderLine();
		file << "|"<< setw(14)<<"Pid"<<"|"<< setw(10)<<"Brand"<<"|"<< setw(10)<<"Price"<<"|"<< setw(10)<<"Quantity"<<"|"<< setw(10)<<"Line Amount"<<endl;
		for(int i=0; i < orderLine.size(); i++) {
			double lineAmount = orderLine[i]->getProduct()->getPrice() *  orderLine[i]->getQuantity();
			totalAmount+=lineAmount;
			file <<  "|" << setw(14)<< orderLine[i]->getProduct()->getPid() << "|" << setw(10)<< orderLine[i]->getProduct()->getBrand() << "|" << setw(10)<<  orderLine[i]->getProduct()->getPrice() << "|"<< setw(10) <<orderLine[i]->getQuantity() << "|"<< setw(10) <<lineAmount <<endl;

		}
		file << "Total amount: "<< totalAmount<<endl;
		file << "_______________________________________________________________________"<<endl;
		file.close();
		cout << "Successfully writen into Transaction.txt"<<endl;
	}
	else{

		cout<<"[Warning] File cannot open!"<<endl;
	}
}

/*
*	Function readAllTransactions read all transactions from the Transaction.txt 
*/
vector<Transaction *> PosMenu::readAllTransactions()
{
	vector<Transaction *> transactionList;
	string line;
	ifstream myfile ("Transaction.txt");
	if (myfile.is_open())
	{
		Transaction * transaction =  new Transaction();
		string invoiceNo;
		string tDate;
		string tTime;
		double tAmount;
		vector<OrderProduct *> orderLine;
		while ( myfile.good() )
		{

			getline (myfile,line);

			if(line.find("Invoice Number:")!=std::string::npos)
			{
				invoiceNo =trim(line.erase(0,15));	// Retrieve the invoiceNo from the string
				transaction->setInvoiceNo(invoiceNo);
			}
			else if(line.find("Date:")!=std::string::npos)
			{
				tDate = trim(line.erase(0,5));	// Retrieve the tDate from the string
				transaction->setTDate(tDate);
			}
			else if(line.find("Time:")!=std::string::npos)
			{
				tTime = trim(line.erase(0,5));	// Retrieve the tTime from the string
				transaction->setTTime(tTime);
			}
			else if(line.find("Pid")!=std::string::npos)
			{
				continue; // Skip the title line
			}
			else if(line.find("|")!=std::string::npos)
			{

				OrderProduct * orderProduct = new OrderProduct();
				Products * prod = new Products();

				vector<string> order = split(line, '|'); // Split the product line by the '|'
				prod->setPid(trim(order[1]));
				prod->setBrand(trim(order[2]));
				prod->setPrice(atoi((trim(order[3])).c_str()));
				orderProduct->setProduct(prod);
				orderProduct->setQuantity(atoi((trim(order[4])).c_str()));
				orderProduct->setAmount(atof((trim(order[5])).c_str()));
				orderLine.push_back(orderProduct);

			}
			else if(line.find("Total amount:")!=std::string::npos)
			{
				tAmount = atof((trim(line.erase(0,13))).c_str());	// Retrieve the tAmount from the string
				transaction->setTAmount(tAmount);

			}
			else if(line.find("_____")!=std::string::npos) // End of the transaction
			{
				transaction->setOrderLine(orderLine);
				transactionList.push_back(transaction);
				transaction = new Transaction();
				orderLine.clear();
			}
		}
		myfile.close();//file closed
	}

	else {cout << "[Warning] Unable to open file"<<endl; }

	return transactionList;
}

/*
*	Function readTransactionByInvoiceNo read the specific transactions by the invoice no. 
*/
Transaction * PosMenu::readTransactionByInvoiceNo(string invoiceNo){
	vector<Transaction *> transactionList =readAllTransactions();

	for(int i =0;i< transactionList.size();i++)
	{
		if(transactionList[i]->getInvoiceNo().compare(invoiceNo) ==0)
		{
			return transactionList[i];
		}
	}

	return 0;
}
/*
*	Function viewTheLatestInvoice displays the newly transaction. 
*/
void  PosMenu::viewTheLatestInvoice(){
	vector<Transaction *> transactionList =readAllTransactions();

	transactionList[transactionList.size()-1]->TransactionInfo();
}

/*
*	Function viewTheLatestInvoice displays the total amount of sale . 
*/
void PosMenu::viewSaleReport()
{
	vector<Transaction *> transactionList =readAllTransactions();
	double totalMoney=0;
	for(int i =0;i< transactionList.size();i++)
	{
		totalMoney+=transactionList[i]->getTAmount();
		cout<<"Invoice No: "<<setw(15)<< transactionList[i]->getInvoiceNo() <<" received $"<<transactionList[i]->getTAmount()<<endl;
	}
	cout << "Total sale amount $"<<totalMoney<<endl;

}





//////////////////////////////////////////////////////////////////////////

////////////////Validation
/*
*	Function isExistProducts check the itemNo is valid or not . 
*/

int PosMenu::isExistProducts(int itemNo)
{
	if(itemNo <products.size())
		return true;

	return false;
}


/*
*	Function isExistProductInShoppingCart check the product is existing or not from the cart. 
*/
int PosMenu::isExistProductInShoppingCart(Products * product)
{
	for(int i = 0; i < shoppingCart.size(); i++)
	{
		if(product->getPid()==shoppingCart[i]->getProduct()->getPid()) 
		{
			return true;
		} // end if

	} // end for 

	return false;
}
//////////////////////////////////////////////////////////////////////////

// Method for Int to String
string IntToString (int a)
{
	string str;
	ostringstream temp;
	temp<<a;
	return temp.str();
}
// Method for trimming string whitespace
string trim(string str)
{
	std::stringstream trimmer;
	trimmer << str;
	trimmer >> str;
	return str;
}
// Method for split the string by the delim
vector<string> &split(const string &s, char delim,vector<string> &elems) {
	stringstream ss(s);
	string item;
	while (getline(ss, item, delim)) {
		elems.push_back(item);
	}
	return elems;
}


vector<string> split(const string &s, char delim) {
	vector<string> elems;
	split(s, delim, elems);
	return elems;
}